#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
物品数据模型

定义物品相关的数据模型，包括：
1. SQLAlchemy ORM 模型 - 用于数据库操作
2. Pydantic 模型 - 用于数据验证和序列化

功能特性：
- 物品创建和管理
- 物品分类和标签
- 物品所有者关联
- 数据验证和序列化

作者: FastAPI 学习项目
创建时间: 2024
"""

from datetime import datetime
from typing import Optional, List
from decimal import Decimal
from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey, Boolean, Numeric
from sqlalchemy.orm import relationship
from pydantic import BaseModel, validator, Field

from app.database.connection import Base


class Item(Base):
    """
    物品 SQLAlchemy ORM 模型
    
    定义物品表的数据库结构和关系
    
    Attributes:
        id: 物品唯一标识符
        title: 物品标题
        description: 物品描述
        price: 物品价格
        category: 物品分类
        tags: 物品标签
        is_available: 是否可用
        image_url: 物品图片URL
        owner_id: 物品所有者ID（外键）
        created_at: 创建时间
        updated_at: 更新时间
        owner: 物品所有者（关联关系）
    """
    
    __tablename__ = "items"
    
    id = Column(Integer, primary_key=True, index=True, comment="物品ID")
    title = Column(
        String(200), 
        nullable=False, 
        index=True,
        comment="物品标题"
    )
    description = Column(
        Text, 
        nullable=True,
        comment="物品描述"
    )
    price = Column(
        Numeric(10, 2), 
        nullable=True,
        comment="物品价格"
    )
    category = Column(
        String(100), 
        nullable=True, 
        index=True,
        comment="物品分类"
    )
    tags = Column(
        String(500), 
        nullable=True,
        comment="物品标签（逗号分隔）"
    )
    is_available = Column(
        Boolean, 
        default=True,
        comment="是否可用"
    )
    image_url = Column(
        String(255), 
        nullable=True,
        comment="物品图片URL"
    )
    owner_id = Column(
        Integer, 
        ForeignKey("users.id"), 
        nullable=False,
        comment="物品所有者ID"
    )
    created_at = Column(
        DateTime, 
        default=datetime.utcnow,
        comment="创建时间"
    )
    updated_at = Column(
        DateTime, 
        default=datetime.utcnow, 
        onupdate=datetime.utcnow,
        comment="更新时间"
    )
    
    # 关联关系：物品所有者
    owner = relationship("User", back_populates="items")
    
    def __repr__(self):
        """
        物品对象的字符串表示
        
        Returns:
            str: 物品对象的描述字符串
        """
        return f"<Item(id={self.id}, title='{self.title}', owner_id={self.owner_id})>"
    
    def to_dict(self):
        """
        将物品对象转换为字典
        
        Returns:
            dict: 包含物品信息的字典
        """
        return {
            "id": self.id,
            "title": self.title,
            "description": self.description,
            "price": float(self.price) if self.price else None,
            "category": self.category,
            "tags": self.tags.split(",") if self.tags else [],
            "is_available": self.is_available,
            "image_url": self.image_url,
            "owner_id": self.owner_id,
            "created_at": self.created_at,
            "updated_at": self.updated_at
        }
    
    @property
    def tag_list(self) -> List[str]:
        """
        获取标签列表
        
        Returns:
            List[str]: 标签列表
        """
        if self.tags:
            return [tag.strip() for tag in self.tags.split(",") if tag.strip()]
        return []
    
    def add_tag(self, tag: str):
        """
        添加标签
        
        Args:
            tag: 要添加的标签
        """
        current_tags = self.tag_list
        if tag not in current_tags:
            current_tags.append(tag)
            self.tags = ",".join(current_tags)
    
    def remove_tag(self, tag: str):
        """
        移除标签
        
        Args:
            tag: 要移除的标签
        """
        current_tags = self.tag_list
        if tag in current_tags:
            current_tags.remove(tag)
            self.tags = ",".join(current_tags)


# Pydantic 模型用于数据验证和序列化

class ItemBase(BaseModel):
    """
    物品基础 Pydantic 模型
    
    包含物品的基本信息字段
    """
    title: str = Field(
        ..., 
        min_length=1, 
        max_length=200,
        description="物品标题，长度1-200个字符"
    )
    description: Optional[str] = Field(
        None, 
        max_length=2000,
        description="物品描述，最多2000个字符"
    )
    price: Optional[float] = Field(
        None, 
        ge=0,
        description="物品价格，必须大于等于0"
    )
    category: Optional[str] = Field(
        None, 
        max_length=100,
        description="物品分类，最多100个字符"
    )
    tags: Optional[List[str]] = Field(
        None,
        description="物品标签列表"
    )
    is_available: bool = Field(
        True,
        description="是否可用"
    )
    image_url: Optional[str] = Field(
        None,
        description="物品图片URL"
    )
    
    @validator('title')
    def validate_title(cls, v):
        """
        验证物品标题
        
        Args:
            v: 标题值
            
        Returns:
            str: 验证后的标题
            
        Raises:
            ValueError: 当标题格式不正确时抛出异常
        """
        if not v or len(v.strip()) == 0:
            raise ValueError('物品标题不能为空')
        return v.strip()
    
    @validator('price')
    def validate_price(cls, v):
        """
        验证物品价格
        
        Args:
            v: 价格值
            
        Returns:
            float: 验证后的价格
            
        Raises:
            ValueError: 当价格不合法时抛出异常
        """
        if v is not None and v < 0:
            raise ValueError('物品价格不能为负数')
        if v is not None and v > 999999.99:
            raise ValueError('物品价格不能超过999999.99')
        return v
    
    @validator('tags')
    def validate_tags(cls, v):
        """
        验证物品标签
        
        Args:
            v: 标签列表
            
        Returns:
            List[str]: 验证后的标签列表
        """
        if v is not None:
            # 去除空标签和重复标签
            cleaned_tags = list(set([tag.strip() for tag in v if tag.strip()]))
            if len(cleaned_tags) > 10:
                raise ValueError('标签数量不能超过10个')
            for tag in cleaned_tags:
                if len(tag) > 50:
                    raise ValueError('单个标签长度不能超过50个字符')
            return cleaned_tags
        return v
    
    @validator('category')
    def validate_category(cls, v):
        """
        验证物品分类
        
        Args:
            v: 分类值
            
        Returns:
            str: 验证后的分类
        """
        if v and len(v.strip()) == 0:
            return None
        return v.strip() if v else v


class ItemCreate(ItemBase):
    """
    创建物品的 Pydantic 模型
    
    继承物品基础模型，用于创建新物品
    """
    pass


class ItemUpdate(BaseModel):
    """
    更新物品信息的 Pydantic 模型
    
    所有字段都是可选的，只更新提供的字段
    """
    title: Optional[str] = Field(
        None, 
        min_length=1, 
        max_length=200,
        description="物品标题"
    )
    description: Optional[str] = Field(
        None, 
        max_length=2000,
        description="物品描述"
    )
    price: Optional[float] = Field(
        None, 
        ge=0,
        description="物品价格"
    )
    category: Optional[str] = Field(
        None, 
        max_length=100,
        description="物品分类"
    )
    tags: Optional[List[str]] = Field(
        None,
        description="物品标签列表"
    )
    is_available: Optional[bool] = Field(
        None,
        description="是否可用"
    )
    image_url: Optional[str] = Field(
        None,
        description="物品图片URL"
    )
    
    @validator('title')
    def validate_title(cls, v):
        """
        验证物品标题
        """
        if v is not None and (not v or len(v.strip()) == 0):
            raise ValueError('物品标题不能为空')
        return v.strip() if v else v
    
    @validator('price')
    def validate_price(cls, v):
        """
        验证物品价格
        """
        if v is not None and v < 0:
            raise ValueError('物品价格不能为负数')
        if v is not None and v > 999999.99:
            raise ValueError('物品价格不能超过999999.99')
        return v
    
    @validator('tags')
    def validate_tags(cls, v):
        """
        验证物品标签
        """
        if v is not None:
            cleaned_tags = list(set([tag.strip() for tag in v if tag.strip()]))
            if len(cleaned_tags) > 10:
                raise ValueError('标签数量不能超过10个')
            for tag in cleaned_tags:
                if len(tag) > 50:
                    raise ValueError('单个标签长度不能超过50个字符')
            return cleaned_tags
        return v


class ItemResponse(ItemBase):
    """
    物品响应的 Pydantic 模型
    
    用于 API 响应，包含物品的完整信息
    """
    id: int = Field(
        ...,
        description="物品ID"
    )
    owner_id: int = Field(
        ...,
        description="物品所有者ID"
    )
    created_at: datetime = Field(
        ...,
        description="创建时间"
    )
    updated_at: datetime = Field(
        ...,
        description="更新时间"
    )
    
    class Config:
        """
        Pydantic 配置
        
        启用 ORM 模式以支持从 SQLAlchemy 模型创建
        """
        from_attributes = True
        json_encoders = {
            datetime: lambda v: v.isoformat()
        }


class ItemWithOwner(ItemResponse):
    """
    包含所有者信息的物品响应模型
    
    用于需要显示物品所有者信息的场景
    """
    owner: dict = Field(
        ...,
        description="物品所有者信息"
    )


class ItemSearch(BaseModel):
    """
    物品搜索的 Pydantic 模型
    
    用于物品搜索和过滤
    """
    keyword: Optional[str] = Field(
        None,
        description="搜索关键词"
    )
    category: Optional[str] = Field(
        None,
        description="分类过滤"
    )
    min_price: Optional[float] = Field(
        None, 
        ge=0,
        description="最低价格"
    )
    max_price: Optional[float] = Field(
        None, 
        ge=0,
        description="最高价格"
    )
    tags: Optional[List[str]] = Field(
        None,
        description="标签过滤"
    )
    is_available: Optional[bool] = Field(
        None,
        description="是否可用过滤"
    )
    owner_id: Optional[int] = Field(
        None,
        description="所有者ID过滤"
    )
    
    @validator('max_price')
    def validate_price_range(cls, v, values):
        """
        验证价格范围
        
        Args:
            v: 最高价格
            values: 其他字段值
            
        Returns:
            float: 验证后的最高价格
            
        Raises:
            ValueError: 当价格范围不合法时抛出异常
        """
        if v is not None and 'min_price' in values and values['min_price'] is not None:
            if v < values['min_price']:
                raise ValueError('最高价格不能小于最低价格')
        return v


class ItemStats(BaseModel):
    """
    物品统计信息的 Pydantic 模型
    
    用于显示物品相关的统计数据
    """
    total_items: int = Field(
        ...,
        description="物品总数"
    )
    available_items: int = Field(
        ...,
        description="可用物品数"
    )
    categories: List[dict] = Field(
        ...,
        description="分类统计"
    )
    average_price: Optional[float] = Field(
        None,
        description="平均价格"
    )
    popular_tags: List[dict] = Field(
        ...,
        description="热门标签"
    )